import org.grailsext.annotation.Privileged
import org.grailsext.util.Utils

class UserController extends BaseController {

	// Set redirect action after authentication. TBD
	static DEFAULT_REDIRECT_AFTER_AUTH = [controller:'user', action:'list']
	
	def beforeInterceptor = [action:this.&auth, except:['login','authenticate','logout']]

    static allowedMethods = [save: "POST", update: "POST", delete: "POST"]

    def index = {
        redirect(action: "list", params: params)
    }

	def login = {
		println "Redirect to user login page."
		render(view:'login')
	}

	def authenticate = {
		println "Authenticate user login."

		if(!params.userName || !params.password){
			println "User name or password is not filled."
			flash.message = "${message(code: 'user.auth.blank.message')}"
			redirect(action:'login')
			return
		}

		User u = User.findByUserName(params.userName)
		if(!u){
			println "No such user"
			flash.message = "${message(code: 'user.auth.invalid.name.message', args: [params.userName])}"
			redirect(action:'login')
			return
		}
		
		if(u && u.password && u.password != params.password.encodeAsMD5()){
			println "Password wrong. " + params.password
			flash.message = "${message(code: 'user.auth.invalid.password.message', args: [params.userName], default:'Invalid password for user: {0}')}"
			redirect(action:'login')
			return
		}
		
		// Login success
		session.userId = u.id
		session.userName = u.userName
		session.department = u.department
		session.nickName = u.firstName
		println "${u.userName} login success."
//		def redirectParams = session.originalRequestParams?:DEFAULT_REDIRECT_AFTER_AUTH
//		println "redirect to: ${redirectParams}"
		if(session.originalRequestParams) {
			redirect(session.originalRequestParams)
		} else {
			redirect(uri: "")
		}
	}

	def logout = {
		println "user ${session.userName} logout."
		session.userId = null
		session.userName = null
		session.department = null
		session.nickName = null
		render(view:'login')
	}

    @Privileged(privileges = ['SHOW_USER'])
    def list = {
        params.max = Math.min(params.max ? params.int('max') : 10, 100)
        [userList: User.list(params), userTotal: User.count()]
    }

	@Privileged(privileges = ['CREATE_USER'])
    def create = {
        def user = new User()
        user.properties = params
        return [user: user]
    }

	@Privileged(privileges = ['CREATE_USER'])
    def save = {
		println "UserController.save-->"
		println "params: ${params}"
        def user = new User(params)
		// Check user level
		if(user && user.userName == "admin") {
			flash.message = "${message(code: 'user.admin.cant.create.message', params:[params.userName])}"
			redirect(action: "list")
			return
		}

		// Selected roles
		def roleIds = Utils.convertStrings2Longs(params.selectedRoles)
		if(roleIds){
			def criteria = Role.createCriteria()
			def roles = criteria.list{
				'in'('id', roleIds)
			}
			println roles
			for(r in roles){
				println "Attach Role to User: " + r
				user.addToRoles(r)
			}
		} else {
			println "Role IDs: " + roleIds
		}

		user.creationTime = Calendar.getInstance()
		
        if (user.save(flush: true)) {
            flash.message = "${message(code: 'default.created.message', args: [message(code: 'user.label', default: 'User'), user.userName])}"
            redirect(action: "show", id: user.id)
        }
        else {
            render(view: "create", model: [user: user])
        }
		println "<--UserController.save"
    }

    @Privileged(privileges = ['SHOW_USER'])
    def show = {
        def user = User.get( params.id )
        if (!user) {
            flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.userName])}"
            redirect(action: "list")
        }
        else {
            [user: user]
        }
    }

	@Privileged(privileges = ['UPDATE_USER'])
    def edit = {
        def user = User.get(params.id)
        if (!user) {
            flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.userName])}"
            redirect(action: "list")
        }
        else {
            return [user: user]
        }
    }

	@Privileged(privileges = ['UPDATE_USER'])
    def update = {
		println "UserController.update-->"
		println "params: ${params}"
		String rootRoleName = grailsApplication.config.modules.role.root.name
		String rootUserName =grailsApplication.config.modules.user.root.name
			
        def user = User.get(params.id)
        if (user) {
            if (params.version) {
                def version = params.version.toLong()
                if (user.version > version) {
                    user.errors.rejectValue("version", "default.optimistic.locking.failure", [message(code: 'user.label', default: 'User')] as Object[], "Another user has updated this User while you were editing")
                    render(view: "edit", model: [user: user])
                    return
                }
            }

			// User name no change
			params.remove("userName")
			
			// Password is no change
			if(params.password == null || params.password == '******'){
				params.remove("password")
			}
			
            user.properties = params
			
			// Selected roles
			String[] selectedRoles
			if(params.selectedRoles == null){
				// Dismiss relationship with any roles.
				user.roles = null
				
			} else {
				if(params.selectedRoles instanceof String){
					selectedRoles = [params.selectedRoles]
				} else {
					selectedRoles = params.selectedRoles
				}
				println selectedRoles
				println selectedRoles.length
				
				// Find Roles set to user.
				if(selectedRoles.length > 0){
					def roleIds = Utils.convertStrings2Longs(selectedRoles)
					println("Role IDs: " + roleIds)
					def roleCriteria = Role.createCriteria()
					def roles = roleCriteria.list{'in'('id', roleIds)}
					user.roles = roles
				}
			}
				
			// Admin User must contain super role.
			if(user.userName == rootUserName) {
				Role rootRole = Role.findByRoleName(rootRoleName)
				if(! (rootRole.id in selectedRoles)) {
					if(user.roles == null) {
						user.roles = [rootRole]
					} else {
						user.roles.add(rootRole)
					}
				}
			}


			
            if (!user.hasErrors() && user.save(flush: true)) {
                flash.message = "${message(code: 'default.updated.message', args: [message(code: 'user.label', default: 'User'), user.userName])}"
                redirect(action: "show", id: user.id)
            }
            else {
                render(view: "edit", model: [user: user])
            }
        }
        else {
            flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.userName])}"
            redirect(action: "list")
        }
		println "<--UserController.update"
    }
	
	// Change Password of current signed in user(not for reset password).
	def pwd = {
		println "change password"
        def user = User.get(session.userId)
        if (!user) {
            flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.userName])}"
            redirect(action: "list")
        }
        else {
			if(!grailsApplication.config.modules.user.root.name == user.userName) {
				flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.userName])}"
				redirect(action: "list")
			} else {
	            return [user: user]				
			}
        }
	}
	
	// Save new password.
	def updateNewPwd = {
		
		// Check old passwords matching.
		if(params.newPassword1 != params.newPassword2) {
			flash.message = "${message(code: 'user.two.new.pwds.not.match.message')}"
			redirect(action: "pwd" )
			return
		}
		
		// Check new password.
		if(!params.newPassword1) {
			flash.message = "${message(code: 'user.new.pwd.illegal.message')}"
			redirect(action: "pwd" )
			return
		}
		
        def user = User.get(session.userId)
        if (!user) {
            flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.userName])}"
            redirect(action: "list")
			return
			
		} else {
			
			// Check old password.
			if(params.oldPassword.encodeAsMD5() != user.password) {
				flash.message = "${message(code: 'user.old.pwd.invalid.message')}"
				redirect(action: "pwd" )
				return
				
			} else {
				user.password = params.newPassword1.encodeAsMD5()
				
				if (!user.hasErrors() && user.save(flush: true)) {
					flash.message = "${message(code: 'user.change.pwd.message')}"
					redirect(action: "list" )
					
				} else {
					flash.message = user.errors["password"]
					redirect(action: "pwd")
				}

			}
		}
	}

	@Privileged(privileges = ['DELETE_USER'])
    def delete = {
        def user = User.get(params.id)
		if(user && user.userName == "admin") {
			flash.message = "${message(code: 'user.admin.cant.delete.message')}"
			redirect(action: "list")
			return
		}
        if (user) {
            try {
                user.delete(flush: true)
                flash.message = "${message(code: 'default.deleted.message', args: [message(code: 'user.label', default: 'User'), params.userName])}"
                redirect(action: "list")
            }
            catch (org.springframework.dao.DataIntegrityViolationException e) {
                flash.message = "${message(code: 'default.not.deleted.message', args: [message(code: 'user.label', default: 'User'), params.userName])}"
                redirect(action: "show", id: params.id)
            }
        }
        else {
            flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.userName])}"
            redirect(action: "list")
        }
    }
}
